#include <stdio.h>
#include <string.h>

#include "..//include//createvfs.h"
#include "..//include//n_ary.h"
#include "..//include//hash.h"
#include "..//include//vfs_errorcodes.h"

struct Block b;
struct header headervar;
struct FD file_desc;

int addfileop (char dest_dir_name[], char file_name[], char data_path[], char filename_g[])
{
    int i;
    int j;
    int blkNo; // Block number to store in the FD
    int used_des;
    char c;
    char data[1024]="";
    char d[2];
    char completePath[100]="";
    char *ext;
    int count;
    int l1;
    int flag_size = 0;
    
    count = 0;
    
    FILE *fp_src;
    FILE *fp_dest;	
	if ((strcmp(dest_dir_name,"") == 0) || (strcmp(file_name,"") == 0) || (strcmp(data_path,"") == 0)){
		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_00);
		return 0;
	}
	
	if(strstr(file_name,"/")){
		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_02);
		return 0;
	}
	
	l1 = strlen(dest_dir_name);
	
	if(dest_dir_name[l1-1]!='/')
	{
		strcat(dest_dir_name,"/");
	}
	


    // Read data from the source file

    fp_src = fopen(data_path, "rt");
    if (fp_src == NULL)
    {
        printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_05);
        return 0;
    }
    while(!feof(fp_src))
    {
        c = getc(fp_src);
        d[0]=c;
        d[1]='\0';
        if(c != EOF){
            strcat(data,d);
            count = count + 1;
        }
        if(count>=1024) {
        	flag_size = 1;
        	break;
        }
    }

    strcat(data,"\0");

    fclose(fp_src);
    if (flag_size == 1) {
    	printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_06); // File too large
        return 0;
    }

    // Concatenate the dir name and file name

    strcpy(completePath,"");
    strcat(completePath,dest_dir_name);
    //strcat(completePath,"/");
    strcat(completePath,file_name);
    strcat(completePath,"\0");

    fp_dest = fopen(filename_g, "rb+");

    if (fp_dest == NULL)
    {
        printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_05); // Cannot write to data file
        return 0;
    }

    else
    {
    	if(searchTree(root, dest_dir_name) == 0) {
    		printf("addfile_FAILURE %s\n",ERR_VFS_MOVEFILE_02); // File already exists
                return 0;
    	}
    	// Check if file already exists
    	if(searchTree(root, completePath) == 1){
    		printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_03); // File already exists
                return 0;
    	}

        

        rewind (fp_dest);
        fread(&headervar, sizeof(struct header), 1, fp_dest);

        rewind (fp_dest);

        fseek (fp_dest, (LABEL_SIZE*sizeof(char) + 2*(sizeof(int)) + sizeof(struct FD)), SEEK_SET);
        for(j=2; j<=TOTAL_DESC; j++)
        {
            fread (&file_desc, sizeof(struct FD), 1, fp_dest);
            if(strcmp(file_desc.path,completePath)==0)
            {
                printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_03); // File already exists
                return 0;
            }
        }

        rewind (fp_dest);
        fread(&headervar, sizeof(struct header), 1, fp_dest);
        used_des = headervar.used_desc;
        if (used_des == TOTAL_DESC || num_used_blocks == num_blocks)
        {
           printf("addfile_FAILURE %s\n",ERR_VFS_ADDFILE_04); // File system FULL
           return 0;

        }

        rewind(fp_dest);
        fseek(fp_dest, sizeof(struct header), SEEK_SET);
        fread(&freelist, sizeof(freelist), 1, fp_dest);
        
        for(i=0; i<num_blocks; i++)
        {
            if(freelist[i] == 0)  // use it
            {
                // Operation: create a file (assign a block), set the location to 1 and break immediately

                // Write to block
                fseek(fp_dest, (sizeof(struct header)+ sizeof(freelist) + sizeof(struct Block)*i), SEEK_SET);
                fread(&b, sizeof(struct Block), 1, fp_dest);
                strcpy(b.blk,data);
                fseek(fp_dest, sizeof(struct header)+(sizeof(freelist))+sizeof(struct Block)*i, SEEK_SET);
                fwrite(&b, sizeof(struct Block), 1, fp_dest);

                //Write to FD
                rewind (fp_dest);
                fseek (fp_dest, (LABEL_SIZE*sizeof(char) + 2*(sizeof(int))) + sizeof(struct FD), SEEK_SET);
                for(j=1; j<=TOTAL_DESC; j++)
                {
                    fread (&file_desc, sizeof(struct FD), 1, fp_dest);
                    if(strcmp(file_desc.name,"\0")==0)
                    {
                        strcpy(file_desc.path,completePath); // Storing the full path, including file name
                        strcpy(file_desc.name,file_name);
                        file_desc.blockno = i+1;
                        rewind(fp_dest);
                        fseek (fp_dest, (LABEL_SIZE*sizeof(char) + 2*(sizeof(int))+ sizeof(struct FD)*j), SEEK_SET);
                        fwrite(&file_desc, sizeof(struct FD), 1, fp_dest);
                        rewind (fp_dest);
                        freelist[i] = 1; // VERY IMPORTANT! This indicates that block i+1 has been used.
                        rewind(fp_dest);
                        fseek(fp_dest, sizeof(struct header), SEEK_SET);
                        fwrite(&freelist, sizeof(freelist),1, fp_dest);
                        num_used_blocks = num_used_blocks + 1;
                        break;
                    }
                }

                break;
            }

        }
        rewind (fp_dest);
        fread(&headervar, sizeof(struct header), 1, fp_dest);
        used_des = headervar.used_desc;
        used_des = used_des + 1; //IMPORTANT! Increment the no. of used descriptors.
        //printf("No. of used des: %d\n", used_des);
        headervar.used_desc = used_des;
        rewind (fp_dest);
        fwrite(&headervar, sizeof(struct header), 1, fp_dest);
    }

    // Insert into the nary tree and hash table

    if(searchTree(root, completePath) == 0){
    	root = insert(root,completePath);    	
    	hashfile(file_name,dest_dir_name);
    	
    }
    fclose(fp_dest);
    return 1;
}
